#include "app.hpp"
#include "module1.hpp"
#include "module2.hpp"
#include "camera.hpp"
#include "tool1.hpp"
#include "tool2.hpp"
#include "sorfttimer_v2.hpp"
#include "cJSON.hpp"
#include "base64.hpp"
#include "ws_client_app.hpp"
#include "miniz.hpp"
#include "myyolodetect.hpp"

using namespace std;
int send_stream_handler(void);

void app_init(void)
{
    std::cout << "app init" << endl;

    module1_init();

    module2_init();

    // camera_init();

    tool1_init();

    tool2_init();

    Init_onnx_yolov8();

    st_start_cb_timer(APP_TASK_TIME, 1000, TIM_LOCK, TIM_CYCLE, app_task_process);

}

void app_task_process(uint16_t id)
{
    static int time = 0;
    if (id == APP_TASK_TIME)
    {
        time += 10;
        // std::cout << "Time:" << time << endl;
        get_image();
        return;
    }
    if (id == APP_TASK_CAMERA)
    {
        std::cout << "Camera" << endl;
        send_stream_handler();
        return;
    }
    if (id == APP_TASK_CONNECT)
    {
        st_start_cb_timer(APP_TASK_CAMERA, 1000, TIM_LOCK, TIM_CYCLE, app_task_process);
        std::cout << "Conenct" << endl;
        return;
    }
    if (id == APP_TASK_DISCONNECT)
    {
        st_close_timer(APP_TASK_CAMERA, TIM_DESTROYED);
        std::cout << "DisConenct" << endl;
        return;
    }
}

/*
{
    "Name": "dvc_gin",
    "Type": 1,
    "Key": 1234,
    "Action": 3,
    "TargetName": "lot",
    "TargetType": 3,
    "TargetKey": 5678,
    "DataLen": 6,
    "Data":"base64",
}
*/

int send_string_to_server(uint8_t *data, uint32_t len)
{
    int ret = 0;
    cJSON *back_itemp = cJSON_CreateObject();
    cJSON_AddStringToObject(back_itemp, "Name", "esp32");
    cJSON_AddNumberToObject(back_itemp, "Type", C_TYPE_LOT);
    cJSON_AddNumberToObject(back_itemp, "Key", 5678);
    cJSON_AddNumberToObject(back_itemp, "Action", C_ACTION_SEND_DATA);

    cJSON_AddStringToObject(back_itemp, "TargetName", "gin_pc");
    cJSON_AddNumberToObject(back_itemp, "TargetType", C_TYPE_PC);
    cJSON_AddNumberToObject(back_itemp, "TargetKey", 1234);

    cJSON_AddNumberToObject(back_itemp, "DataLen", len);
    cJSON_AddStringToObject(back_itemp, "Data", (char *)data);

    char *back_js = cJSON_PrintUnformatted(back_itemp);
    if (back_js)
    {
        int send_len = strlen(back_js);
        if (send_len > 0)
        {
            // ret = websocket_app_sen_text((uint8_t *)back_js, send_len);
            std::string send_str(back_js);
            ws_send_text_data_to_server(send_str);
            ret = send_len;
            // if (ret <= 0)
            // {
            //     ret = 1;
            //     if (back_js)
            //     {
            //         free(back_js);
            //     }
            //     if (back_itemp)
            //     {
            //         cJSON_Delete(back_itemp);
            //     }
            //     return ret;
            // }
        }
    }

    if (back_js)
    {
        free(back_js);
    }

    if (back_itemp)
    {
        cJSON_Delete(back_itemp);
    }
    return ret;
}
/**
 * miniz 压缩处理，压缩成功需要释放内存
 */
uint8_t *moniz_compress(uint8_t *src_buff, uint32_t src_len, uint32_t *out_len)
{
    uint8_t *outdata = NULL;
    // tdefl_status state;
    // tdefl_compressor miniz;
    // tdefl_init(&miniz, *NULL, (void *)NULL, TDEFL_DEFAULT_MAX_PROBES | TDEFL_WRITE_ZLIB_HEADER);
    // tdefl_compress_buffer(&miniz, (void *)buffer, sizeof(buffer), TDEFL_FINISH);
    // state = tdefl_compress(&miniz, (void *)src_buff, &src_len, (void *)out_buf, (size_t *)out_len, TDEFL_DEFAULT_MAX_PROBES | TDEFL_WRITE_ZLIB_HEADER);

    *out_len = 0;

    outdata = (uint8_t *)tdefl_compress_mem_to_heap((void *)src_buff, (size_t)src_len, (size_t *)out_len, TDEFL_DEFAULT_MAX_PROBES | TDEFL_WRITE_ZLIB_HEADER);

    if (outdata && (*out_len > 0))
    {
        return outdata;
    }
    else
    {
        return NULL;
    }
}

/**
 * miniz 解除压缩处理，成功需要释放内存
 */
uint8_t *moniz_decompress(uint8_t *src_buff, uint32_t src_len, uint32_t *out_len)
{
    uint8_t *outdata = NULL;

    *out_len = 0;

    outdata = (uint8_t *)tinfl_decompress_mem_to_heap((void *)src_buff, (size_t)src_len, (size_t *)out_len, TINFL_FLAG_PARSE_ZLIB_HEADER);

    if (outdata && (*out_len > 0))
    {
        return outdata;
    }
    else
    {
        return NULL;
    }
}

#define ONE_READ_PACK_LEN 300
#define PACK_SIZE 1024
uint8_t send_buf[PACK_SIZE + 4] = {'\0'};

int send_stream_handler(void)
{
    int res = 0;
    size_t _jpg_buf_len = 0;
    uint8_t *_jpg_buf = NULL;

    /*获取视频帧*/
    std::vector<unsigned char> image_raw = get_image();

    if (image_raw.empty())
    {
        res = 1;
    }
    else
    {
        // 获取 char * 指针
        _jpg_buf = reinterpret_cast<uint8_t *>(image_raw.data());
        // 获取数据长度
        _jpg_buf_len = image_raw.size();

        std::cout << "Image size:" << _jpg_buf_len << endl;
    }

    /*发送一帧数据*/
    if (res == 0)
    {

        int RealSend = 0;
        int NeedLen = 0;
        int Len_Base64 = 0;
        uint32_t ZipLen = 0;

/*mini zlib 压缩处理*/
#if 0
        std::cout << "Src size:" << _jpg_buf_len << endl;

        uint8_t *ZipData = moniz_compress(_jpg_buf, _jpg_buf_len, &ZipLen);

        std::cout << "Zip size:" << ZipLen << endl;

        if (ZipData)
        {
            uint8_t *Data_base64 = base64_encode(ZipData, ZipLen, (size_t *)&Len_Base64);
            uint8_t *Need_Send_Base64 = Data_base64;
            free(ZipData);
#else
        if (1)
        {
            uint8_t *Data_base64 = base64_encode(_jpg_buf, _jpg_buf_len, (size_t *)&Len_Base64);
            uint8_t *Need_Send_Base64 = Data_base64;
#endif

            if (Need_Send_Base64)
            {
                std::cout << "Base64 size:" << Len_Base64 << endl;

                send_string_to_server((uint8_t *)"DataHead", 8);
                while (Len_Base64 > 0)
                {
                    if (Len_Base64 > PACK_SIZE)
                    {
                        NeedLen = PACK_SIZE;
                    }
                    else
                    {
                        NeedLen = Len_Base64;
                    }

                    memset(send_buf, '\0', sizeof(send_buf));
                    memcpy(send_buf, Need_Send_Base64, NeedLen);

                    RealSend = send_string_to_server(send_buf, NeedLen); /*这里返回的长度是加上了json 协议头的长度，请注意*/
                    if (RealSend <= 0)
                    {
                        res = 1;
                        break;
                    }

                    Need_Send_Base64 += NeedLen;
                    Len_Base64 -= NeedLen;
                }
                send_string_to_server((uint8_t *)"DataTail", 8);
            }
            // mbedtls_base64_encode();

            if (Data_base64)
            {
                free(Data_base64);
            }
        }
    }
    return res;
}